package cz.semjobKB.controller;


import com.google.gwt.thirdparty.guava.common.io.Files;
import cz.semjobKB.conllx.api.IDocument;
import cz.semjobKB.conllx.api.impl.ProcessTreexOutput;
import cz.semjobKB.controller.api.IController;
import cz.semjobKB.extract.service.TextExtractorService;
import cz.semjobKB.gui.DisplayLayout;
import cz.semjobKB.invoke_treex.service.TreexService;
import cz.semjobKB.knowledge.api.IExtractedKnowledge;
import cz.semjobKB.knowledge.api.ITerminologyItem;
import cz.semjobKB.knowledge.api.ITripleItem;
import cz.semjobKB.search.api.ISearchRules;
import cz.semjobKB.search.api.RuleCorrectnessException;
import cz.semjobKB.search.config.impl.SearchConfiguration;
import cz.semjobKB.search.service.impl.SearchService;
import cz.semjobKB.virtuoso.document.api.IDocumentDetail;
import cz.semjobKB.virtuoso.document.api.IResourceDetail;
import cz.semjobKB.virtuoso.document.api.ITerminologyDetail;
import cz.semjobKB.virtuoso.document.api.ITripleDbItem;
import cz.semjobKB.virtuoso.service.impl.DatabaseService;
import cz.semjobKB.virtuoso.utils.ELanguage;
import cz.semjobKB.virtuoso.utils.ETriplePart;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * Controller operates as interface between view and model modules
 */
@Component
public class Controller implements IController {
	
	private Logger logger = Logger.getLogger(Controller.class);
	
	@Autowired
	TextExtractorService textExtractorService;
	
	@Autowired
	TreexService treexService;
	
	@Autowired
	ProcessTreexOutput processTreexOutput;
	
	@Autowired
	SearchService searchService;
	
	@Autowired
	DatabaseService databaseService;
	
	@Autowired
	SearchConfiguration searchConfiguration;
	
	@Autowired
	DisplayLayout displayLayout;
	
	File documentBase = new File ( System.getProperty( "user.home" ) + File.separator + 
			"semjobFiles");

	public void processDocument(File documentFile, File fileStrategy) {
		
		File storedFile = new File(documentBase, documentFile.getName());		
		
		if (!documentFile.getAbsolutePath().startsWith(documentBase.getAbsolutePath())) {
			try {
				Files.copy(documentFile, storedFile);
			} catch (IOException e) {
				displayLayout.showError("IOException");
				return;
			}
		} else {
			storedFile = documentFile;
		}
		
		File textFile = textExtractorService.extractText(storedFile.getAbsolutePath());
		if (textFile == null) {
			displayLayout.showError("Text couldnt be extracted");
			return;
		}
		
		File strategy = fileStrategy;
		
		if(!strategy.exists()) {
			displayLayout.showError("Strategy doesn't exists");
			return;
		}
		
		File conllFile = treexService.invokeLinguisticPocessing(textFile.getAbsolutePath());
		
		if(conllFile == null) {
			displayLayout.showError("Invoking Treex failed");
			return;
		}
		
		IDocument documentTree;
		try {
			documentTree = processTreexOutput.parseDocument(FileUtils.readFileToString(conllFile), FileUtils.readFileToString(textFile));
		} catch (IOException e) {
			displayLayout.showError("Couldnt create Document Tree");
			return;
		} catch (Exception e) {
			displayLayout.showError("Couldnt create Document Tree");
			return;
		}
		if (documentTree == null) {
			displayLayout.showError("Couldnt create Document Tree");
			return;
		}
		
		ISearchRules searchRules = searchConfiguration.loadXMLConfiguration(strategy.getAbsolutePath());
		
		if (searchRules == null) {
			displayLayout.showError("Invoking Treex failed");
			return;
		}
		
		IExtractedKnowledge extractedKnowledge;
		try {
			extractedKnowledge = searchService.extractBase(documentTree, searchRules);
		} catch (RuleCorrectnessException e) {
			displayLayout.showError("Strategy Mallformed");
			return;
		}
		if(extractedKnowledge == null) {
			displayLayout.showError("Couldnt extract knowledge");
			return;
		}
		LinkedHashMap<ITripleItem, Boolean> triples = new LinkedHashMap<ITripleItem, Boolean>();		
		for (ITripleItem tripleItem : extractedKnowledge.getTriples()) {
			if ((databaseService.searchTriples(tripleItem.getSubjectLemma(), tripleItem.getPredicateLemma(), tripleItem.getObjectLemma())).size() > 0) {
				triples.put(tripleItem, true);
			} else {
				triples.put(tripleItem, false);
			}
		}
		
		LinkedHashMap<ITerminologyItem, Boolean> terminology = new LinkedHashMap<ITerminologyItem, Boolean>();		
		for (ITerminologyItem terminologyItem : extractedKnowledge.getTerminology()) {
			List<ITerminologyDetail> foundTerminology = databaseService.getTerminologyDetail(terminologyItem.getLemma()); 
			if (foundTerminology.size() == 0) {
				terminology.put(terminologyItem, false);
			} else {
				boolean hasPositiveOccurence = false;
				for (ITerminologyDetail terminologyDetail : foundTerminology) {
					if (terminologyDetail.getTotalCount() > 0) {
						hasPositiveOccurence = true;
					}
				}
				if (hasPositiveOccurence) { 
					terminology.put(terminologyItem, true);
				} else {
					terminology.put(terminologyItem, false);
				}
			}	
		}
		
		displayLayout.showDocumentPreSave(triples, terminology, extractedKnowledge, storedFile, this);		
		
	}
	
	public void storeFinalDocument(IExtractedKnowledge finalKnowledge, File storedFile) {
		
		IDocumentDetail documentDetail = databaseService.storeDocument(finalKnowledge, storedFile, ELanguage.CZ);		
		displayLayout.showDocumentDetail(documentDetail);
		
	}

	public void resourceDetail(ETriplePart triplePart,
			String resourceName) {
		if (triplePart == null) {
			if(!resourceName.isEmpty()) {
				List<ITerminologyDetail> terminologyDetail = databaseService.getTerminologyDetail(resourceName);
				displayLayout.showTerminologyDetail(terminologyDetail);
			}
		}
		if (triplePart == ETriplePart.SUBJECT) {
			if(!resourceName.isEmpty()) {
				List<IResourceDetail> termDetail = databaseService.getResourceDetail(resourceName);
				displayLayout.showTermDetail(termDetail);
			}
		}
		if (triplePart == ETriplePart.PREDICATE) {
			if(!resourceName.isEmpty()) {
				List<IResourceDetail> termDetail = databaseService.getResourceDetail(resourceName);
				displayLayout.showTermDetail(termDetail);
			}
		}
		if (triplePart == ETriplePart.OBJECT) {
			if(!resourceName.isEmpty()) {
				List<IResourceDetail> termDetail = databaseService.getResourceDetail(resourceName);
				displayLayout.showTermDetail(termDetail);
			}
		}
	}

	public void suggestTriples(String subject, String predicate,
			String object) {
		if(subject.isEmpty()) {
			subject = null;
		}
		if(predicate.isEmpty()) {
			predicate = null;
		}
		if(object.isEmpty()) {
			object = null;
		}
		if(subject != null || predicate != null || object != null) {
			List<ITripleDbItem> triples = databaseService.searchTriples(subject, predicate, object);
			displayLayout.showSuggestedTriples(triples);
		}
	}

	public void findDocument(String subject, String predicate,
			String object) {
		if(!subject.isEmpty() || !predicate.isEmpty() || !object.isEmpty()) {
			List<IDocumentDetail> documents = databaseService.searchDocument(subject, predicate, object);
			displayLayout.showResultDocuments(documents);
		}
	}

	public void findDocument(String terminology) {
		if(!terminology.isEmpty()) {
			List<IDocumentDetail> documents = databaseService.searchDocument(terminology, 0);
			displayLayout.showResultDocuments(documents);
		}
	}	
}
